package com.authstr.utils;

import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 便捷的对Request的参数进行查询,并对属性进行维护
 * 请注意!
 * 参数（parameter）的值只能读取不能修改，读取可以使用request.getParameter()读取；
 * 属性（attribute）的值既可以读取亦可以修改，读取可以使用request.setAttribute(),设置可使用request.getAttribute()
 * 所有查询都会优先查询 属性
 * @author 杨梦豪
 * @time 2020年2月23日00:19:38
 */
public class RequestUtils {

    /**
     * 获取当前会话的request
     * @return
     */
    public static HttpServletRequest getRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null){
            return null;
//            throw new Exception("无法从上下文环境中获取Request对象");
        }
        return ((ServletRequestAttributes)requestAttributes).getRequest();
    }

    /**
     * 以Map<String, String> 的方式 获取request里的所有属性或参数
     * @return
     */
    public static Map<String, String> getRequestParameters() {
        HashMap<String, String> values = new HashMap<String, String>();
        HttpServletRequest request=getRequest();
        if (request == null) {
            return values;
        } else {
            Enumeration enums = request.getParameterNames();
            while(enums.hasMoreElements()) {
                String paramName = (String)enums.nextElement();
                String paramValue =get(paramName);
                values.put(paramName, paramValue);
            }
            return values;
        }
    }

    /**
     * 获取一个指定key的 属性或者参数
     * 如果是数组,以逗号分隔,合并为一个字符串
     * @param key
     * @return
     */
    public static String get(String key){
        //优先从 属性(Attribute) 中获取值
        Object attributeObject=getRequest().getAttribute(key);
        if(attributeObject==null){
            //否则从 参数(parameter) 获取
            String[] values=getRequest().getParameterValues(key);
            return values!=null&&values.length!=0?String.join(",",values):null;
        }else{
            return attributeObject.toString();
        }
    }

    /**
     * 获取一个指定key的属性或参数,并将获取到的值转换为Integer
     * 转换失败返回null.
     * @param key
     * @return
     */
    public static Integer getInteger(String key){
        String res=get(key);
        try {
            return Integer.valueOf(res);
        }catch (NumberFormatException e){
            return null;
        }
    }


    /**
     * 获取一个指定key的属性或参数,以Array的形式获取
     * @param key
     * @return
     */
    public static String[] getArray(String key){
        Object attributeObject=getRequest().getAttribute(key);
        if(attributeObject==null){
            String[] res=getRequest().getParameterValues(key);
            //先判断是否为空的字符串
            boolean isEmptyString=null !=res && res.length==1 && !StringUtils.hasText(res[0]);
            return isEmptyString?null:getRequest().getParameterValues(key);
        }else{
            if(attributeObject instanceof String){
                return new String[] {attributeObject.toString()};
            }
            return attributeObject instanceof  String[]?(String[])attributeObject:null;
        }
    }

    /**
     * 尝试使用Request的参数或属性数据封装出指定类型的对象
     * 建议属性的类型保持一致,否则可能导致错误的赋值或异常
     * @param clazz 指定的class
     * @param <T>
     * @return
     */
//    public static  <T> T getObject(Class<T> clazz){
//        try {
//            //通过clazz 创建 对象
//            T target = clazz.newInstance();
//            BeanUtils.populate(target, getRequestParameters());
//            return target;
//        } catch (Exception e) {
//            return null;
//        }
//    }

    /**
     * 从属性中获取添加过的对象
     * @param clazz
     * @param key
     * @param <T>
     * @return
     */
    public  static  <T> T getAttributeObject(Class<T> clazz,String key){
        return (T)getRequest().getAttribute(key);
    }

    /**
     * 向request里添加属性
     * @param key
     * @param value
     */
    public static void add(String key,String value){
        getRequest().setAttribute(key,value);
    }

    /**
     * 向request里添加属性
     * @param key
     * @param value
     */
    public static void addInteger(String key,Integer value){
        getRequest().setAttribute(key,value);
    }

    /**
     * 向request里添加属性
     * @param key
     * @param value
     */
    public static void addArray(String key,String[] value){
        getRequest().setAttribute(key,value);
    }

    /**
     * 向request里添加属性
     * @param key
     * @param value
     */
    public static void addObject(String key,Object value){
        getRequest().setAttribute(key,value);
    }

    /**
     * 从参数或属性map中获取指定key的值,验证是否有值
     * 不会考虑属性添加的Object
     * @param key
     * @return
     */
    public static boolean hasKeyText(String key) {
        return StringUtils.hasText(get(key))||getArray(key)!=null;
    }

    /**
     * 验证属性的值是否存在,如果存在,拼接sql并向map添加值
     * 例:
     *          verifyAndSet(" and a.name = :user_name ",sql, kv);
     *
     *          等价于：
     *
     *          if(RequestUtils.hasKeyText("user_name")){
     *             sql.append(" and a.name = :user_name ");
     *             kv.put("user_name", RequestUtils.get("user_name");
     *          }
     * @param sql_snippet
     * @param sql
     * @param kv
     */
    public  static  void verifyAndSet(String sql_snippet,StringBuffer sql,Map<String,Object> kv){
        //从sql片段匹配出占位符
        String key=getSqlPrecompileKey(sql_snippet);
        if(RequestUtils.hasKeyText(key)){
            sql.append(sql_snippet);
            kv.put(key,RequestUtils.get(key));
        }
    }

    /**
     * 验证属性的值是否存在,如果存在,拼接sql并以模糊查询的方式向map添加值
     * @param sql_snippet
     * @param sql
     * @param kv
     */
    public  static  void verifyAndLikeSet(String sql_snippet,StringBuffer sql,Map<String,Object> kv){
        //从sql片段匹配出占位符
        String key=getSqlPrecompileKey(sql_snippet);
        if(RequestUtils.hasKeyText(key)){
            sql.append(" "+sql_snippet+" ");
            kv.put(key,"%"+RequestUtils.get(key)+"%");
        }

    }

    /**
     * 从sql中获取预编译的参数名称
     * 例: and a.id= :id     返回 id
     *     select * from :tableName where 1=1  返回 tableName
     * @param sql_snippet
     * @return
     */
    public static String getSqlPrecompileKey(String sql_snippet){
        Pattern p = Pattern.compile("[:]\\w+");
        Matcher m = p.matcher(sql_snippet);
        String re=m.find()?m.group():null;
        if(re==null||re.length()<=1){
            System.out.println("无法从sql片段中获取预编译占位符,sql片段为:"+sql_snippet+",占位符应为以 : 开头的单词.出错的类为RequestUtils,方法为verifyAndSet");
            return null;
        }
        return re.substring(1);
    }


}
